home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / ewrtgn10.zip / EWRTFGEN.PAS < prev   
Pascal/Delphi Source File  |  1993-07-17  |  25KB  |  1,048 lines

  1.                               { EWRTFGEN }
  2.  
  3. (*********  Source code (C) Copyright 1992, by L. David Baldwin   *********)
  4. (*********  Source code (C) Copyright 1993, by Patrick Philippot  *********)
  5. (*********                All Rights Reserved                     *********)
  6.  
  7. {************************************************}
  8. {                                                }
  9. { E! for Windows                                 }
  10. { (c) - Patrick Philippot - 1992,1993            }
  11. {                                                }
  12. { EWRTFGEN Extension DLL - version 1.0           }
  13. {                                                }
  14. { This DLL translates the current text to a      }
  15. { .RTF file suitable for the Windows Help        }
  16. { compiler, provided it complies to the syntax   }
  17. { defined by RTFGEN (see doc.).                  }
  18. {                                                }
  19. {************************************************}
  20.  
  21. {$C MOVEABLE DEMANDLOAD DISCARDABLE}
  22.  
  23. Library EWRTFGEN;
  24. {$IFDEF DEBUG}
  25. {$A+,G+,B-,D+,E-,F+,I-,N-,R+,S+,V-,L+,Q+,Y+,K+,X+}
  26. {$ELSE}
  27. {$A+,G+,B-,D-,E-,F+,I-,N-,R-,S-,V-,L-,Q-,Y-,K+,X+}
  28. {$ENDIF}
  29.  
  30. Uses WinProcs, WinTypes, EWAPIIMP, Strings;
  31.  
  32. Const
  33.   TwipsPerSpace = 120;
  34.   DefaultFont : String[6] = '2';
  35.   DefaultFontSize : String[10] = '20';
  36.   ParaChar : Char = '`';
  37.   Tokenleng = 28;         {Max symbol length}
  38.   Tab = #9;
  39.   MaxRes = 13;
  40.  
  41. Type
  42.   Symb = (
  43.     OtherChar, Comma, Colon, SemiColon, Lbrack, Rbrack, Dot, Slash,
  44.     LLbrack, RRbrack, OtherPunct, Ident, EolSy, Space, ParaSy, TabSy,
  45.     BuildTagSy, TopicSy, TitleSy, KeyWordSy, BrowseSy,
  46.     TopicStart, TopicEnd, DocStartSy, DocEndSy, CommandSy, BMCSy, BMLSy,
  47.     BMRSy, FontCommand, Number, BlockStartSy, BlockEndSy);
  48.   SymString = string[14];
  49.  
  50. Var
  51.   Sy, SaveSy : Symb;
  52.  
  53. Const
  54.   ResWord : array[1..MaxRes] of SymString = (
  55.     '\buildtag', '\topic', '\title', '\keyword', '\browse', '\bmc', '\bml',
  56.     '\bmr', '\docstart', '\docend', '\tab', '\blockstart', '\blockend');
  57.   ResSy : array[1..MaxRes] of Symb = (
  58.     BuildTagSy, TopicSy, TitleSy, KeyWordSy, BrowseSy, BMCSy, BMLSy,
  59.     BMRSy, DocStartSy, DocEndSy, TabSy, BlockStartSy, BlockEndSy);
  60.  
  61. Type
  62.   TokenString = string[Tokenleng];
  63.   String127 = string[127];
  64.   Filestring = string[79];
  65.   PairType = array[0..1] of Char;
  66.  
  67. Var
  68.   BrackCount, LineNo, Chi, ErrCount : Integer;
  69.   Pair : Word;
  70.   Spair : PairType absolute Pair;
  71.   LCh : Char absolute Pair;
  72.   UCh : Char;
  73.   St : String127;
  74.   ErrFlag, EofInf, InInclude, InTopic : Boolean;
  75.   SourceName : Filestring;
  76.   Outf : Text;
  77.   Value : LongInt;
  78.   LCToken : TokenString;
  79.   OutString, GlobalHeader, TopicHeader : String;
  80.   BlockHeader : array[1..4] of String;
  81.   BIndex : Integer;
  82.   OutName : FileString;
  83.   LineCount : integer;
  84.  
  85. const
  86.   RTFTitle : PChar = 'Translate to RTF';
  87.  
  88. var
  89.   SaveExit   : Pointer;  { Save ExitProc }
  90.   RTFEntryId : longint;  { Entry Id for the "Translate to RTF" menu }
  91.  
  92. {-------------Error}
  93. procedure Error(II :Integer; S : String127);
  94.  
  95. Var
  96.   X,Y       : Integer;
  97.   ActualCol : integer;
  98.   Msg       : array[0..127] of char;
  99.  
  100. begin
  101.   if II > 2 then
  102.     ActualCol := II - 3
  103.   else
  104.     ActualCol := 0;
  105.   Lineno := Pred(Lineno);
  106.   if Lineno < 0 then
  107.     Lineno := 0;
  108.   EWGotoXY(ActualCol, Lineno);
  109.   StrPCopy(Msg, S);
  110.   EWWriteMessage(Msg);
  111.   ErrFlag := true;
  112. end;
  113.  
  114. {-------------SetWaitCursor}
  115. procedure SetWaitCursor(state : boolean);
  116.  
  117. const
  118.   OldCursor : HCursor = 0;
  119.  
  120. begin
  121.   if state then
  122.     OldCursor := SetCursor(LoadCursor(0, idc_Wait))
  123.   else if OldCursor <> 0 then
  124.     SetCursor(OldCursor);
  125. end;
  126.  
  127.  
  128. {-------------Positn}
  129. function Positn(Pat, Src : String; I : Integer) : Integer;
  130. {-Find the position of a substring in a string starting at the Ith char}
  131.  
  132. var
  133.   N : Integer;
  134.  
  135. begin
  136.   if I < 1 then
  137.     I := 1;
  138.   Delete(Src, 1, I-1);
  139.   N := Pos(Pat, Src);
  140.   if N = 0 then
  141.     Positn := 0
  142.   else
  143.     Positn := N+I-1;
  144. end;
  145.  
  146. {-------------HexString}
  147. procedure HexString(Number : integer; var Result : String);
  148.  
  149. var
  150.   Tmp : integer;
  151.   i   : integer;
  152.  
  153. begin
  154.   for i := 1 to 2 do begin
  155.     Tmp := Number and $F;
  156.     Number := Number shr 4;
  157.     if Tmp >= 10 then
  158.       Result[3-i] := Chr(Tmp - 10 + Ord('a'))
  159.     else
  160.       Result[3-i] := Chr(Tmp + Ord('0'));
  161.   end;
  162.   Result[0] := Char(2);
  163. end;
  164.  
  165. {-------------ConvertForeign}
  166. procedure ConvertForeign;
  167. {-Makes sure that accented characters will be processed correctly}
  168.  
  169. var
  170.   HexStr : String[2];
  171.   RTFStr : String[4];
  172.   i      : word;
  173.  
  174. begin
  175.   i := 1;
  176.   while not ErrFlag and (i <= Length(OutString)) do begin
  177.     if Ord(OutString[i]) > $A0 then begin
  178.       HexString(Ord(OutString[i]), HexStr);
  179.       RTFStr := '\''' + HexStr;
  180.       if Length(OutString) + 4 <= 255 then begin
  181.         Delete(OutString, i , 1);
  182.         Insert(RTFStr, OutString, i);
  183.         Inc(i, 3);
  184.       end else
  185.         Error(i, 'Could not replace ANSI character with RTF command. Please split line.');
  186.     end;
  187.     Inc(i);
  188.   end;
  189. end;
  190.  
  191. {-------------OutFile}
  192. procedure OutFile(S : String);
  193.  
  194. var
  195.   WriteIt : boolean;
  196.   Leng, I : Integer;
  197.  
  198. begin
  199. {-A hard to find bug is mismatched braces. Keep count of these so can keep track of matching.}
  200.   I := 0;
  201.   repeat
  202.     I := Positn('{', S, I+1);
  203.     if (I > 0) then
  204.       if not ((I > 1) and (S[I-1] = '\')) then
  205.         Inc(BrackCount);
  206.   until I = 0;
  207.   repeat
  208.     I := Positn('}', S, I+1);
  209.     if (I > 0) then
  210.       if not ((I > 1) and (S[I-1] = '\')) then
  211.         Dec(BrackCount);
  212.   until I = 0;
  213.  
  214.   {-Try to avoid hanging spaces on end of lines as editors delete them}
  215.   Leng := Length(OutString)+Length(S);
  216.   WriteIt := (Leng >= 75) and (OutString[Length(OutString)] <> ' ') or (Leng >= 200);
  217.   if WriteIt then begin
  218.     ConvertForeign;
  219.     WriteLn(Outf, OutString);
  220.     OutString := S;
  221.   end else
  222.     OutString := OutString+S;
  223.   if IOResult <> 0 then
  224.     Error(Lineno, 'I/O Error while writing Output File');
  225. end;
  226.  
  227. {-------------Flush}
  228. procedure Flush;
  229.  
  230. begin
  231.   if Length(OutString) > 0 then begin
  232.     ConvertForeign;
  233.     WriteLn(Outf, OutString);
  234.     OutString := '';
  235.   end;
  236. end;
  237.  
  238. {-------------GetCh}
  239. procedure GetCh;
  240. {-Return next char in Uch and Lch with Uch in upper case. Ignore comments}
  241.  
  242. Var
  243.   Comment : Boolean;
  244.  
  245.   procedure GetchBasic;
  246.   {-Read a character and a character pair}
  247.   begin
  248.     if Chi<=Ord(St[0]) then begin  {NOTE: pair has the same address as lch}
  249.       Pair := MemW[DSeg : Ofs(St[Chi])];
  250.       if (LCh=Tab) and not InTopic then
  251.         LCh:=' ';
  252.       UCh := UpCase(LCh);
  253.       Chi := Chi+1;
  254.     end else
  255.       if Lineno < LineCount then begin
  256.         St := StrPas(EWGetLineAt(Lineno));
  257.         Inc(LineNo);
  258.         St:=St+^M;  {Add EOL}
  259.         Chi:=1;
  260.         GetCh;
  261.       end else begin
  262.         EofInf:=True;
  263.         if Comment then
  264.           Error(Lineno, 'Open Comment at End of Input File');
  265.       end;
  266.   end;
  267.  
  268. begin  {Getch}
  269.   repeat
  270.     if EofInf then
  271.       Error(Lineno, 'Unexpected End of Input File');
  272.     Comment:=False;
  273.     GetchBasic;
  274.     if ErrFlag then
  275.       Exit;
  276.     if (SPair='(*') then begin
  277.       Comment:=True;
  278.       repeat
  279.         GetchBasic;
  280.       until ErrFlag or (SPair='*)');
  281.       if not ErrFlag then
  282.         GetchBasic;  {pass by the '*'}
  283.     end;
  284.   until ErrFlag or not Comment;
  285. end;
  286.  
  287. {-----------IsPair}
  288. function IsPair : Boolean;
  289.  
  290. Const
  291.   Limit = 8;
  292.   PA : array[1..Limit] of PairType = (
  293.      '[[', ']]', '\[', '\]', '\\', '\`',
  294.      '\{', '\}');        {!! <- if '`' made optional, change!!}
  295. Var
  296.   I : Integer;
  297.   Was : Pairtype;
  298.  
  299. begin
  300.   IsPair := False;
  301.   for I := 1 to Limit do
  302.     if PA[I] = Spair then begin
  303.       Was := SPair;
  304.       Sy := OtherPunct;
  305.       IsPair := True;
  306.       GetCh;
  307.       case I of
  308.         5,7,8 : LCToken := Was;
  309.         1     : Sy := LLbrack;
  310.         2     : Sy := RRbrack;
  311.         else
  312.           LCToken := LCh;
  313.       end;
  314.       GetCh;
  315.       Exit;
  316.     end;
  317. end;
  318.  
  319. {-------------GetNumber}
  320. function GetNumber : Boolean;  {Pick up a Number}
  321.  
  322. Var
  323.   Done : Boolean;
  324.   Code : Integer;
  325.  
  326. begin
  327.   case UCh of
  328.       '0'..'9' : LCToken := '';
  329.      else begin
  330.        GetNumber := False;
  331.        Exit;
  332.      end;
  333.   end;
  334.   GetNumber := True;
  335.   Sy  := Number;
  336.   Done := False;
  337.   if not EofInf then
  338.     while not ErrFlag and not Done do
  339.       case UCh of
  340.         '0'..'9' :
  341.                begin
  342.                LCToken := LCToken+UCh;
  343.                GetCh;
  344.                end;
  345.         else
  346.           Done := True;
  347.       end;
  348.   Val(LCToken, Value, Code);
  349. end;
  350.  
  351. {-------------GetCommand}
  352. function GetCommand : Boolean;  {Pick up a Command}
  353.  
  354. Label 2;
  355.  
  356. const
  357.   MaxFC = 10;
  358.   FontCommands : array[1..MaxFC] of string[6] =
  359.     ('f', 'fs', 'b', 'i', 'strike', 'ul', 'ulw', 'uld', 'uldb',
  360.      'plain');
  361.  
  362. Var
  363.   Done : Boolean;
  364.   I : Integer;
  365.   AlphaOnly : TokenString;
  366.  
  367. begin
  368.   GetCommand := False;
  369.   if UCh <> '\' then
  370.     Exit;
  371.   GetCommand := True;
  372.   Sy := CommandSy;
  373.   LCToken := LCh;
  374.   AlphaOnly := '';
  375.   GetCh;
  376.   Done := False;
  377.   if not EofInf then begin
  378.     while not ErrFlag and not Done do
  379.       case LCh of
  380.         'a'..'z' :
  381.             begin
  382.               if Length(LCToken)<Tokenleng then begin
  383.                 Inc(LCToken[0]);
  384.                 LCToken[Length(LCToken)] := LCh;
  385.                 Inc(AlphaOnly[0]);
  386.                 AlphaOnly[Length(AlphaOnly)] := LCh;
  387.               end;
  388.               GetCh;
  389.             end;
  390.         else
  391.           Done := True;
  392.       end;
  393.     if LCh = '-' then begin
  394.       if Length(LCToken)<Tokenleng then begin
  395.         Inc(LCToken[0]);
  396.         LCToken[Length(LCToken)] := LCh;
  397.       end;
  398.       GetCh;
  399.     end;
  400.     Done := False;
  401.     while not ErrFlag and not Done do
  402.       case LCh of
  403.         '0'..'9' :
  404.             begin
  405.               if Length(LCToken)<Tokenleng then begin
  406.                 Inc(LCToken[0]);
  407.                 LCToken[Length(LCToken)] := LCh;
  408.               end;
  409.               GetCh;
  410.             end;
  411.         else
  412.           Done := True;
  413.        end;
  414.     end;
  415.  
  416.   for I := 1 to MaxRes do
  417.     if LCToken = ResWord[I] then begin
  418.       Sy := ResSy[I];
  419.       GOTO 2;
  420.     end;
  421.   if not InTopic then
  422.     for I := 1 to MaxFC do
  423.       if AlphaOnly = FontCommands[I] then begin
  424.         Sy := FontCommand;
  425.         GoTo 2;
  426.       end;
  427.   2 :    {account for possible space after command}
  428.   if Length(LCToken)<Tokenleng then begin
  429.     Inc(LCToken[0]);
  430.     LCToken[Length(LCToken)] := ' ';
  431.   end;
  432.   if UCh = ' ' then
  433.     GetCh;  {use up a space}
  434. end;
  435.  
  436. {-------------GetIdent}
  437. function GetIdent : Boolean;  {Pick up a Symbol}
  438.  
  439. Var
  440.   Done : Boolean;
  441.   I : Integer;
  442.  
  443. begin
  444.   GetIdent := False;
  445.   case UCh of
  446.       'A'..'Z', '_' : ;
  447.      else
  448.        Exit;
  449.   end;
  450.   GetIdent := True;
  451.   Sy := Ident;
  452.   LCToken := LCh;
  453.   GetCh;
  454.   Done := False;
  455.   if not EofInf then
  456.     while not ErrFlag and not Done do
  457.       case UCh of
  458.         'A'..'Z', '0'..'9', '_' :
  459.             begin
  460.               if Length(LCToken)<Tokenleng then begin
  461.                 Inc(LCToken[0]);
  462.                 LCToken[Length(LCToken)] := LCh;
  463.               end;
  464.               GetCh;
  465.             end;
  466.         else
  467.           Done := True;
  468.       end;
  469. end;
  470.  
  471. {-------------GetTopicEnd}
  472. function GetTopicEnd : boolean;
  473.  
  474. begin
  475.   GetTopicEnd := False;
  476.   if UCh <> '-' then
  477.     Exit;
  478.   if Pos('----', St) <> 1 then
  479.     Exit;
  480.   Chi := Length(St)+1;      {ignore remainder of St}
  481.   if not EofInf then
  482.     GetCh;
  483.   GetTopicEnd := True;
  484.   if not InTopic then begin
  485.     Error(Chi, '----- when not within topic');
  486.     Exit;
  487.   end;
  488.   Sy := TopicEnd;
  489. end;
  490.  
  491. {-------------GetTopicStart}
  492. function GetTopicStart : boolean;
  493.  
  494. begin
  495.   GetTopicStart := False;
  496.   if UCh <> '=' then
  497.     Exit;
  498.   if Pos('====', St) <> 1 then
  499.     Exit;
  500.   Chi := Length(St)+1;      {ignore remainder of St}
  501.   if not EofInf then
  502.     GetCh;
  503.   GetTopicStart := True;
  504.   if InTopic then begin
  505.     Error(Chi, '==== when already within topic');
  506.     Exit;
  507.   end;
  508.   Sy := TopicStart;
  509. end;
  510.  
  511. {-----------Punctuation}
  512. function Punctuation : Boolean;
  513. {-Check to see if Uch is a punctuation mark; if so, store the punctuation type in Sy}
  514.  
  515. Var
  516.   I : Integer;
  517.  
  518. Const
  519.   Punct : string[10] = ^M^I' :;[].';
  520.   SyArray : array[1..8] of Symb = (EOLSy, TabSy, Space, Colon, SemiColon, Lbrack, Rbrack, Dot);
  521.  
  522. begin
  523.   Punctuation := False;
  524.   I := Pos(UCh, Punct);
  525.   case I of
  526.     1..8 : Sy := SyArray[I];
  527.     else if UCH = ParaChar then
  528.        Sy := ParaSy
  529.      else
  530.        Exit;
  531.   end;
  532.   Punctuation := True;
  533.   case Sy of
  534.     EOLSy  : LCToken := ' ';
  535.     ParaSy : LCToken := '';
  536.     TabSy  : LCToken := '\tab ';
  537.     else
  538.       LCToken := LCh;
  539.   end;
  540.   GetCh;
  541. end;
  542.  
  543. {-----------Next}
  544. procedure Next;
  545. {-Get the next token on the command line}
  546. begin
  547.   if EofInf then begin
  548.     Error(Lineno, 'Unexpected end of input file');
  549.     Exit;
  550.   end;
  551.   if IsPair then
  552.   else if GetCommand then
  553.   else if GetIdent then
  554.   else if GetNumber then
  555.   else if GetTopicEnd then
  556.   else if GetTopicStart then
  557.   else if Punctuation then
  558.   else begin
  559.     Sy := OtherChar;
  560.     LCToken := LCh;
  561.     if not EOFinf then
  562.       GetCh;
  563.   end;
  564. end;
  565.  
  566. {-------------SkipWhiteSpace}
  567. procedure SkipWhiteSpace;
  568.  
  569. begin
  570.   while not ErrFlag and ((UCh = ' ') or (UCh = Tab)) do
  571.     GetCh;
  572. end;
  573.  
  574. {-------------ParagraphText}
  575. procedure ParagraphText;
  576.  
  577.   procedure DoBitmap;
  578.   var
  579.     S : String[30];
  580.     Count : Integer;
  581.   const
  582.     FileChars : set of char =  ['A'..'Z', 'a'..'z', '0'..'9', '!', '#'..'''', '@', '^'..'`', '~'];
  583.   begin
  584.     OutFile('\{');
  585.     case Sy of
  586.       BMCSy : S := 'bmc ';
  587.       BMRSy : S := 'bmr ';
  588.       BMLSy : S := 'bml ';
  589.       end;
  590.     SkipWhiteSpace;
  591.     Count := 0;
  592.     while not ErrFlag and (LCH in FileChars) do begin
  593.       S := S+LCh;
  594.       GetCh;
  595.       Inc(Count);
  596.     end;
  597.     if (Count > 8) or (Count = 0) then begin
  598.       Error(Chi, 'Filename expected');
  599.       Exit;
  600.     end;
  601.     if LCh = '.' then begin
  602.       S := S+LCh;
  603.       GetCh;
  604.       Count  := 0;
  605.       while not ErrFlag and (LCH in FileChars) do begin
  606.         S := S+LCh;
  607.         GetCh;
  608.         Inc(Count);
  609.       end;
  610.       if (Count > 3) then begin
  611.         Error(Chi, 'Filename expected');
  612.         Exit;
  613.       end;
  614.     end;
  615.     Next;
  616.     OutFile(S+'\}');
  617.   end;
  618.  
  619.   procedure CrossRef;
  620.   var
  621.     SyWas : Symb;
  622.   begin
  623.     SyWas := Sy;
  624.     if Sy = LBrack then
  625.       OutFile('{\uldb ')
  626.     else
  627.       OutFile('{\ul ');
  628.     SkipWhiteSpace;
  629.     Next;
  630.     case Sy of
  631.       BMCSy, BMLSy, BMRSy :
  632.         begin
  633.           DoBitmap;
  634.           while not ErrFlag and (Sy = Space) do
  635.             Next;
  636.         end;
  637.       else begin
  638.         while not ErrFlag and (Sy <> Colon) and (Sy <> EOLSy) do begin
  639.           OutFile(LCToken);
  640.           Next;
  641.         end;
  642.       end;
  643.     end;
  644.     OutFile('}');
  645.     if Sy <> Colon then begin
  646.       Error(Chi, 'Colon expected');
  647.       Exit;
  648.     end;
  649.     Next;   {use up colon}
  650.     while not ErrFlag and (Sy = Space) do
  651.       Next;
  652.     if (Sy <> Ident) and (Sy <> Dot) and (Sy <> Number) then begin
  653.       Error(Chi, 'Syntax Error in cross reference');
  654.       Exit;
  655.     end;
  656.     OutFile('{\v ');
  657.     repeat
  658.       OutFile(LCToken);
  659.       Next;
  660.     until ErrFlag or ((Sy <> Ident) and (Sy <> Dot) and (Sy <> Number));
  661.     OutFile('}');
  662.     while not ErrFlag and (Sy = Space) do
  663.       Next;
  664.     if SyWas = LBrack then begin
  665.       if Sy <> RBrack then
  666.         Error(Chi, '] expected');
  667.     end else if Sy <> RRbrack then
  668.       Error(Chi, ']] expected');
  669.   end;
  670.  
  671. begin
  672.   while not ErrFlag
  673.   and (Sy <> ParaSy)
  674.   and (Sy <> TopicEnd)
  675.   and (Sy <> BlockStartSy)
  676.   and (Sy <> BlockEndSy) do begin
  677.     case Sy of
  678.        EOLSy   : begin
  679.                    OutFile(' ');
  680.                    SkipWhiteSpace;
  681.                  end;
  682.        LBrack,
  683.        LLbrack : CrossRef;
  684.        BMCSy,
  685.        BMLSy,
  686.        BMRSy   : DoBitmap;
  687.        else
  688.          OutFile(LCToken);
  689.     end;
  690.     if ErrFlag then
  691.       Exit;
  692.     Next;
  693.   end;
  694.   if Sy = ParaSy then begin
  695.     repeat
  696.       Next;   {skip trailing stuff, mainly spaces}
  697.     until ErrFlag or (Sy = EOLSy);
  698.     if not ErrFlag then
  699.       Next;
  700.   end;
  701. end;
  702.  
  703. {-------------Paragraph}
  704. procedure Paragraph;
  705.  
  706. var
  707.   Count : Integer;
  708.   S     : String[10];
  709.  
  710. begin
  711.   repeat   {repeat ignores blank lines with spaces}
  712.     while not ErrFlag and (Sy = EOLSy) do begin
  713.       OutFile('\par');
  714.       Next;
  715.     end;
  716.     Count := 0;
  717.     while not ErrFlag and ((Sy = Space) or (Sy = TabSy)) do begin
  718.       if Sy = TabSy then
  719.         Count := ((Count div 5) +1) * 5 + 1
  720.       else
  721.         Inc(Count);
  722.       Next;
  723.     end;
  724.   until ErrFlag or (Sy <> EOLSy);
  725.   if (Sy <> TopicEnd) and (Sy <> BlockStartSy) and (Sy <> BlockEndSy) then begin
  726.     if Count > 0 then begin
  727.       Str(Count * TwipsPerSpace:-1, S);
  728.       OutFile('\li'+S);
  729.     end;
  730.     {at start of each paragraph, output the paragraph commands entered in the headers}
  731.     if BIndex > 0 then
  732.       OutFile('{'+BlockHeader[BIndex])
  733.     else
  734.       OutFile('{'+GlobalHeader+TopicHeader);
  735.     ParagraphText;   {do all the text}
  736.     OutFile('}\par\pard');
  737.     Flush;
  738.   end;
  739. end;
  740.  
  741. {-------------DoTopic}
  742. procedure DoTopic;
  743.  
  744. begin
  745.   OutFile('#{\footnote \pard\plain \sl240 \fs20 # ');
  746.   SkipWhiteSpace;
  747.   Next;
  748.   while not ErrFlag and ((Sy = Ident) or (Sy = Dot) or (Sy = Number)) do begin
  749.     OutFile(LCToken);
  750.     Next;
  751.   end;
  752.   if Sy <> ParaSy then
  753.     Error(Chi, 'Paragraph mark expected')
  754.   else
  755.     Next;
  756.   if not ErrFlag then begin
  757.     OutFile('}');
  758.     Flush;
  759.   end;
  760. end;
  761.  
  762. {-------------DoBrowse}
  763. procedure DoBrowse;
  764.  
  765. var
  766.   Err : boolean;
  767.  
  768. begin
  769.   OutFile('+{\footnote \pard\plain \sl240 \fs20 + ');
  770.   SkipWhiteSpace;
  771.   Next;
  772.   repeat    {Browse symbol can contain many things up to ':' }
  773.     case Sy of
  774.       OtherChar, Comma,
  775.       SemiColon, Lbrack,
  776.       Rbrack,    Dot,
  777.       Slash,     OtherPunct,
  778.       Ident,     Space,
  779.       TabSy,     Number : Err := False;
  780.       else
  781.         Err := True;
  782.     end;
  783.     if Err then begin
  784.       Error(Chi, 'Syntax error in \Browse');
  785.       Exit;
  786.     end;
  787.     OutFile(LCToken);
  788.     Next;
  789.   until ErrFlag or ((Sy = Colon) or (Sy = ParaSy) or (Sy = EOLsy));
  790.   if Sy = Colon then begin
  791.     SkipWhiteSpace;
  792.     Next;
  793.     if Sy <> Number then begin
  794.       Error(Chi, 'Number expected in Browse');
  795.       Exit;
  796.     end;
  797.     OutFile(':'+LCToken);
  798.     SkipWhiteSpace;
  799.     Next;
  800.   end else
  801.     Error(Chi, 'Colon expected');
  802.   if Sy <> ParaSy then
  803.     Error(Chi, 'Paragraph mark expected');
  804.   if not ErrFlag then begin
  805.     OutFile('}');
  806.     Flush;
  807.     Next;
  808.   end;
  809. end;
  810.  
  811. {-------------DoKeyWord}
  812. procedure DoKeyWord;
  813.  
  814. var
  815.   Err : boolean;
  816.   Ch : Char;
  817.   S : String[10];
  818.  
  819. begin
  820.   case Sy of
  821.     KeyWordSy  : Ch := 'K';
  822.     TitleSy    : Ch := '$';
  823.     BuildTagSy : Ch := '*';
  824.   end;
  825.   S := LCToken;   {save for possible error msg}
  826.   OutFile(Ch+'{\footnote \pard\plain \sl240 \fs20 '+Ch+' ');
  827.   SkipWhiteSpace;
  828.   Next;
  829.   repeat    {symbols can contain many things }
  830.     case Sy of
  831.         OtherChar,  Comma,
  832.         Colon,      SemiColon,
  833.         Lbrack,     Rbrack,
  834.         Dot,        Slash,
  835.         OtherPunct, Ident,
  836.         Space,      TabSy,
  837.         Number              : Err := False;
  838.       else
  839.         Err := True;
  840.     end;
  841.     if Err then begin
  842.       Error(Chi, 'Syntax error in '+S);
  843.       Exit;
  844.     end;
  845.     OutFile(LCToken);
  846.     Next;
  847.   until ErrFlag or ((Sy = ParaSy) or (Sy = EOLSy));
  848.   if Sy <> ParaSy then begin
  849.     Error(Chi, 'Paragraph mark expected');
  850.     Exit;
  851.   end;
  852.   OutFile('}');
  853.   Flush;
  854.   Next;
  855. end;
  856.  
  857. {-------------DoPage}
  858. procedure DoPage;
  859. begin
  860.   InTopic := True;
  861.   Next;
  862.   while not ErrFlag and (Sy <> TopicEnd) do
  863.     if Sy = BlockStartSy then begin
  864.       if BIndex >= 4 then begin
  865.         Error(Chi, 'Too many nested blocks');
  866.         Exit;
  867.       end else
  868.         Inc(BIndex);
  869.       BlockHeader[BIndex] := '';
  870.       Next;
  871.       while not ErrFlag and ((Sy <> ParaSy) and (Sy <> EOLSy)) do begin
  872.         if Sy = CommandSy then
  873.           BlockHeader[BIndex] := BlockHeader[BIndex]+LCToken
  874.         else if Sy <> Space then begin
  875.           Error(Chi, 'Command expected');
  876.           Exit;
  877.         end;
  878.         Next;
  879.       end;
  880.       if Sy = ParaSy then
  881.         Next;
  882.       if Sy = EOLSy then
  883.         Next;
  884.     end else if Sy = BlockEndSy then begin
  885.       if BIndex < 1 then begin
  886.         Error(Chi, 'Unmatched \blockend');
  887.         Exit;
  888.       end else
  889.         Dec(BIndex);
  890.       while not ErrFlag and (Sy <> EOLSy) do
  891.         Next;  {\BlockEnd should be on its own line}
  892.       Next;
  893.     end else
  894.       Paragraph;
  895.   if not EofInf then
  896.     Next;
  897.   OutFile('}\page');
  898.   Flush;
  899.   if BIndex <> 0 then begin
  900.     Error(Chi, 'Unmatched \blockstart in previous topic');
  901.     Exit;
  902.   end;
  903.   InTopic := False;
  904.   if BrackCount <> 0 then begin
  905.     Error(Chi, '{..} imbalance in last topic');
  906.     Exit;
  907.   end;
  908. end;
  909.  
  910. {-------------DoDocument}
  911. procedure DoDocument;
  912.  
  913. begin
  914.   Flush;
  915.   Next;
  916.   if Sy <> DocEndSy then
  917.     OutFile('{');
  918.   while not ErrFlag and (Sy <> DocEndSy) do begin
  919.     case Sy of
  920.       TopicSy :        DoTopic;
  921.       KeyWordSy,
  922.       BuildTagSy,
  923.       TitleSy :
  924.                        DoKeyWord;
  925.       BrowseSy :       DoBrowse;
  926.       TopicStart :     begin
  927.                          DoPage;
  928.                          TopicHeader := '';   {get ready for a new topic header string}
  929.                          while not ErrFlag and
  930.                            ((Sy = EOLSy)
  931.                          or (Sy = space)
  932.                          or (Sy = TabSy)) do
  933.                            Next;
  934.                          if Sy <> DocEndSy then
  935.                            Outfile('{');
  936.                        end;
  937.       EolSy :          Next;
  938.       CommandSy :      begin
  939.                          TopicHeader := TopicHeader+LCToken;  {add in commands}
  940.                          Next;
  941.                        end;
  942.       FontCommand :    begin
  943.                          OutFile(LCToken);
  944.                          Next;
  945.                        end;
  946.       else Next;       {ignore other junk}
  947.     end;
  948.     if ErrFlag then
  949.       Exit;
  950.   end;
  951.   Flush;
  952.   OutFile('}');
  953. end;
  954.  
  955. {-------------WRITEHEADING}
  956.  
  957. procedure WriteHeading;
  958.  
  959. begin
  960.   Writeln(Outf, '{\rtf1\ansi \deff0');
  961.   Writeln(Outf, '{\fonttbl{\f0\froman Tms Rmn;}{\f1\fdecor Symbol;}{\f2\fswiss Helv;}');
  962.   Writeln(Outf, '{\f3\fmodern Courier;}');
  963.   Writeln(Outf, '}');
  964.   Writeln(Outf, '{\colortbl;');
  965.   Writeln(Outf, '\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;');
  966.   Writeln(Outf, '\red0\green255\blue0;');
  967.   Writeln(Outf, '\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;');
  968.   Writeln(Outf, '\red255\green255\blue255;}');
  969.   if IOResult <> 0 then begin
  970.     Close(Outf);
  971.     Error(Lineno, 'I/O Error while creating File Header');
  972.   end;
  973. end;
  974.  
  975.  
  976. {-------------EWEXECUTE}
  977. function EWExecute(RoutineId : word) : integer; export;
  978.  
  979. var
  980.  DotPos : word;
  981.  
  982. begin
  983.   SetWaitCursor(true);
  984.   LineCount := EWGetLineCount;
  985.   ErrCount := 0;
  986.   LineNo := 0;
  987.   BIndex := 0;
  988.   BrackCount := 0;
  989.   OutString := '';
  990.   GlobalHeader := '';
  991.   TopicHeader := '';
  992.   EofInf := False;
  993.   InTopic := False;
  994.   ErrFlag := False;
  995.   InInclude := False;
  996.   EWSaveFile(EWGetFileName(EWGetCurrentEditor));
  997.   EWWriteMessage('Compiling...');
  998.   UpdateWindow(EWGetWindowHandle);
  999.   OutName := StrPas(EWGetFileName(EWGetCurrentEditor));
  1000.   DotPos := Pos('.', OutName);
  1001.   if DotPos <> 0 then
  1002.     Delete(OutName, DotPos, 255);
  1003.   OutName := OutName + '.RTF';
  1004.   Assign(Outf, OutName);
  1005.   ReWrite(Outf);
  1006.   WriteHeading;
  1007.   OutFile('\f'+DefaultFont+'\fs'+DefaultFontSize);
  1008.   St[0] := #0;
  1009.   Chi := 1;  {get the reading started}
  1010.   GetCh;
  1011.   Next;
  1012.   while not ErrFlag and not EofInf and (Sy <> DocStartSy) do begin
  1013.     if Sy = CommandSy then
  1014.       GlobalHeader := GlobalHeader+LCToken
  1015.     else if Sy = FontCommand then
  1016.       OutFile(LCToken);    {else ignore}
  1017.     Next;
  1018.   end;
  1019.   if Sy = DocStartSy then
  1020.     DoDocument;
  1021.   Flush;
  1022.   Close(Outf);
  1023.   if ErrFlag then
  1024.     Erase(Outf)
  1025.   else
  1026.     EWWriteMessage('Compiled successfully.');
  1027.   SetWaitCursor(false);
  1028. end;
  1029.  
  1030. procedure LibExit; far;
  1031. begin
  1032.  {-Remove menu item from the User Menu before unloading}
  1033.   EWRemoveMenuEntry(RTFEntryId);
  1034.   ExitProc := SaveExit;
  1035. end;
  1036.  
  1037. exports
  1038.   EWExecute     index 1;
  1039.  
  1040. begin
  1041.   SaveExit := ExitProc;
  1042.   ExitProc := @LibExit;
  1043.  {-Extension attaches itself to the user Menu}
  1044.  { Two commands are made available. Therefore we create two menu entries}
  1045.   RTFEntryId  := EWAddMenuEntry('ewrtfgen', RTFTitle, 0, EWMNU_Extension, 0);
  1046. end.
  1047.  
  1048.